package com.hyh.admin.sys.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hyh.ad.common.constants.Constants;
import com.hyh.ad.common.constants.RedisConstant;
import com.hyh.ad.common.core.domain.AjaxResult;
import com.hyh.ad.common.core.domain.login.LoginUser;
import com.hyh.ad.common.core.domain.model.SysRole;
import com.hyh.ad.common.core.domain.model.SysUser;
import com.hyh.ad.common.core.redis.CacheClient;
import com.hyh.ad.common.utils.ImgUtil;
import com.hyh.ad.common.utils.SecurityUtils;
import com.hyh.ad.common.utils.ServletUtils;
import com.hyh.admin.recommend.RecommendationUserSimilarService;
import com.hyh.admin.recommend.ScoreCalculatorService;
import com.hyh.admin.recommend.UserProfile;
import com.hyh.admin.recommend.UserProfileService;
import com.hyh.admin.sys.mapper.SysUserMapper;
import com.hyh.admin.sys.service.ISysUserService;
import com.hyh.admin.tool.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 系统用户信息表(SysUser)表服务实现类
 * @author hyh
 */

@Slf4j
@Service
public class SysUserServiceImpl implements ISysUserService {
    @Autowired
    private SysUserMapper sysUserMapper;


    @Autowired
    private CacheClient cacheClient;


    @Autowired
    private JwtUtil JwtUtil;

    @Autowired
    private ScoreCalculatorService scoreCalculatorService;

    @Autowired
    private UserProfileService userProfileService;


    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RecommendationUserSimilarService recommendationUserSimilarService;

    @Override
    public AjaxResult login(SysUser sysUser) {
        //查询用户是否存在
        AjaxResult HTTP_CREATED = getAjaxResult(sysUser.getUsername());
        if (HTTP_CREATED != null) return HTTP_CREATED;

        //获取全局唯一标识符
        String uuid = ServletUtils.getParameter("UUID");
        log.info("uuid:{}", uuid);
        UsernamePasswordAuthenticationToken authenticationToken
                = new UsernamePasswordAuthenticationToken(sysUser.getUsername(),
                sysUser.getPassword());
        String checkCode = cacheClient.getObject(RedisConstant.CAPTCHA_PREFIX + uuid);
        if (checkCode == null) {
            return new AjaxResult(HttpStatus.HTTP_CREATED,"验证码已过期");
        }
        if (!checkCode.equalsIgnoreCase(sysUser.getCheckCode())) {
            return new AjaxResult(HttpStatus.HTTP_CREATED, "验证码错误");
        }
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if(Objects.isNull(authenticate.getPrincipal()))
            throw new RuntimeException("用户名或密码错误");
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        SysUser sysUser1 = loginUser.getUser();
        String token = JwtUtil.getToken(loginUser.getUser());
        //清除验证码
        cacheClient.delete(RedisConstant.CAPTCHA_PREFIX + uuid);
        log.info("user1:{}", sysUser1);
        Map<String,String> map = new HashMap<>();
        map.put("token",token);
        return  AjaxResult.success("登陆成功",map);
    }



    @Override
    public AjaxResult register(SysUser user) {
        // 对密码加密
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        LambdaQueryWrapper<SysUser> qw = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<SysUser> qw1 = new LambdaQueryWrapper<>();
        qw1.eq(SysUser::getEmail, user.getEmail());
        qw.eq(SysUser::getUsername, user.getUsername());
        String code = cacheClient.getObject(RedisConstant.REGISTER_EMAIL_CODE + user.getEmail());
        if (code == null)
            return new AjaxResult(HttpStatus.HTTP_BAD_REQUEST,"验证码已过期" ,null );

        if (!code.equals(user.getCheckCode())){
            return new AjaxResult(HttpStatus.HTTP_BAD_REQUEST, "验证码错误", null );
        }
        SysUser sysUser = sysUserMapper.selectOne(qw);
        SysUser sysUser1 = sysUserMapper.selectOne(qw1);

        if (Objects.nonNull(sysUser1)){
            //删除验证码
            cacheClient.delete(RedisConstant.REGISTER_EMAIL_CODE + user.getEmail());
            return  AjaxResult.error("邮箱已注册");
        }

        if(Objects.nonNull(sysUser)){
            //删除验证码
            cacheClient.delete(RedisConstant.REGISTER_EMAIL_CODE + user.getEmail());
            return new AjaxResult(HttpStatus.HTTP_BAD_REQUEST, null, "用户名已存在");
        }
        int insert = sysUserMapper.insert(user);
        insertImgByUserName(user);
        if(insert == 0)
            return new AjaxResult(HttpStatus.HTTP_BAD_REQUEST, null, "注册失败");
        //删除验证码
        cacheClient.delete(RedisConstant.REGISTER_EMAIL_CODE + user.getEmail());
        //生成token
        String token = JwtUtil.getToken(user);
        Map<String,String> map = new HashMap<>();
        map.put("token",token);
        return new AjaxResult(HttpStatus.HTTP_OK, "注册成功", map);
    }

    @Override
    public IPage<SysUser> selectBaseUserList(SysUser sysUser, Page<SysUser> page) {
        LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>(sysUser);
        query.orderByDesc(SysUser::getCreateTime);
        return sysUserMapper.selectPage(page, query);
    }

    @Override
    public SysUser selectBaseUserById(Long id) {
        return sysUserMapper.selectById(id);
    }

    @Override
    public AjaxResult loginByPassword(String username, String password, String code, String uuid) {
        AjaxResult HTTP_CREATED = getAjaxResult(username);
        if (HTTP_CREATED != null) return HTTP_CREATED;

        //调用loadUserByUsername方法
        UsernamePasswordAuthenticationToken authenticationToken
                = new UsernamePasswordAuthenticationToken(username, password);
        String checkCode = cacheClient.getObject( Constants.CAPTCHA_CODE_KEY + uuid);
        if (checkCode == null) {
            return new AjaxResult(HttpStatus.HTTP_CREATED,"验证码已过期");
        }
        if (!checkCode.equalsIgnoreCase(code)) {
            return new AjaxResult(HttpStatus.HTTP_CREATED, "验证码错误");
        }
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if(Objects.isNull(authenticate.getPrincipal()))
            return new AjaxResult(HttpStatus.HTTP_OK, "用户名密码错误");
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        SysUser sysUser1 = loginUser.getUser();
        String token = JwtUtil.getToken(loginUser.getUser());
        //清除验证码
        cacheClient.delete(Constants.CAPTCHA_CODE_KEY + uuid);
        log.info("user1:{}", sysUser1);
        Map<String,String> map = new HashMap<>();
        map.put("token",token);
        return  AjaxResult.success("登陆成功",map);
    }

    //获取一周内系统的访问数量 将数量存入到redis
    @Override
    public AjaxResult getVisit() {
        // TODO 存入redis访问量 开发中
        return AjaxResult.success("开发中");
    }

    @Override
    public int updateStatus(SysUser sysUser) {
        //取出密码进行加密
        sysUser.setPassword(new BCryptPasswordEncoder().encode(sysUser.getPassword()));
        return sysUserMapper.updateById(sysUser);
    }

    @Override
    public int insertSysUser(SysUser sysUser) {
        sysUser.setPassword(new BCryptPasswordEncoder().encode(sysUser.getPassword()));
        return sysUserMapper.insert(sysUser);
    }

    @Override
    public int deleteByIds(Long[] ids) {
        return sysUserMapper.deleteBatchIds(Arrays.asList(ids));
    }

    @Override
    public List<SysRole> selectHasRoles(Long id) {
        return sysUserMapper.selectHasRoles(id);
    }

    @Override
    public SysUser selectUserByUserName(String username) {
        LambdaQueryWrapper<SysUser> qw = new LambdaQueryWrapper<>();
        qw.eq(SysUser::getUsername, username);
        return sysUserMapper.selectOne(qw);
    }

    @Override
    public int updateById(SysUser sysUser) {
        sysUser.setId(SecurityUtils.getLoginUser().getUser().getId());

        // 先查询redis的用户画像
        UserProfile userProfile = userProfileService.getUserProfile(sysUser.getId().toString());

        if (userProfile == null) {
            userProfile = new UserProfile(sysUser, new HashMap<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
        }

        List<UserProfile> existingUsers = new ArrayList<>();
        sysUserMapper.selectList(null).forEach(user -> {
            // 查询所有的用户画像
            if (!user.getId().equals(sysUser.getId())) {  // **排除新用户自己**
                UserProfile userProfileCanvas = userProfileService.getUserProfile(user.getId().toString());
                if (userProfileCanvas != null) {  // **防止空数据**
                    existingUsers.add(userProfileCanvas);
                }
            }
        });

        //赋予新用户推荐结果
        List<String> strings = recommendationUserSimilarService.recommendCoursesForNewUser(userProfile, existingUsers);
        userProfile.setRecommendedCourses(strings);

        // 生成用户画像
        scoreCalculatorService.updateCourseScore(userProfile, null, "other");
        return sysUserMapper.updateById(sysUser);
    }

    @Override
    public SysUser selectById(Long id) {
        //除了密码之外的信息
        SysUser sysUser = sysUserMapper.selectById(id);
        sysUser.setPassword(null);
        return sysUser;
    }

    private AjaxResult getAjaxResult(String username) {
        //查询用户是否存在
        LambdaQueryWrapper<SysUser> qw = new LambdaQueryWrapper<>();
        qw.eq(SysUser::getUsername, username);
        SysUser sysUser2 = sysUserMapper.selectOne(qw);
        if (Objects.isNull(sysUser2))
            return  AjaxResult.success( "用户不存在");
        return null;
    }

    // 生成随机的头像
    public void insertImgByUserName(SysUser user) {
        LambdaQueryWrapper<SysUser> qw = new LambdaQueryWrapper<>();
        qw.eq(SysUser::getUsername, user.getUsername());
        SysUser user1 = sysUserMapper.selectOne(qw);
        if (user1.getAvatar() == null || user1.getAvatar().isEmpty())
            user1.setAvatar(ImgUtil.img[RandomUtil.randomInt(0, ImgUtil.img.length)]);
        sysUserMapper.updateById(user1);
    }
}
